package com.bosssoft.platform.fasttcc.support.spring;

import com.bosssoft.platform.fasttcc.Xid;
import com.bosssoft.platform.fasttcc.impl.XidImpl;
import com.bosssoft.platform.fasttcc.rpc.command.TccCommandHandler;
import com.bosssoft.platform.fasttcc.rpc.command.TccMethodCallCommand;
import com.bosssoft.platform.fasttcc.support.OriginMethodInvoke;
import com.jfireframework.baseutil.StringUtil;
import com.jfireframework.baseutil.TRACEID;
import com.jfireframework.baseutil.reflect.ReflectUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

@WebFilter("/*")
@Component
public class TccHandlerFilter implements Filter
{

    static final         String            CALLID         = "FASTTCC-CALLID";
    static final         String            NODEIDENTIFIER = "FASTTCC-NODEIDENTIFIER";
    static final         String            XID            = "FASTTCC-XID";
    private static final Logger            LOGGER         = LoggerFactory.getLogger(TccHandlerFilter.class);
    @Autowired
    private              TccCommandHandler tccCommandHandler;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException
    {
    }

    @Override
    public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException
    {
        HttpServletRequest request   = (HttpServletRequest) servletRequest;
        String             xidString = request.getHeader(XID);
        if (StringUtil.isNotBlank(xidString))
        {
            String traceId = TRACEID.newTraceId();
            LOGGER.debug("traceId:{} 本次http请求中包含xid:{}", traceId, xidString);
            String requestURI = request.getRequestURI();
            if (requestURI.contains("fasttcc/commit") || requestURI.contains("fasttcc/rollback"))
            {
                LOGGER.debug("traceId:{} 本次请求是完成阶段请求，详细请求为:{}", traceId, requestURI);
                filterChain.doFilter(servletRequest, servletResponse);
                return;
            }
            else
            {
                String callId         = request.getHeader(CALLID);
                String nodeIdentifier = request.getHeader(NODEIDENTIFIER);
                Xid    xid            = new XidImpl();
                ((XidImpl) xid).setGlobalId(StringUtil.hexStringToBytes(xidString));
                TccMethodCallCommand command = new TccMethodCallCommand();
                command.setCallId(callId);
                command.setNodeIdentifier(nodeIdentifier);
                command.setXid(xid);
                LOGGER.debug("traceId:{} 收到上游节点的TCC调用,xid:{},callId:{},nodeIdentifier:{}", traceId, command.getXid(), command.getCallId(), command.getNodeIdentifier());
                try
                {
                    tccCommandHandler.processTccMethodCallCommand(command, new OriginMethodInvoke()
                    {
                        @Override
                        public Object invoke()
                        {
                            try
                            {
                                filterChain.doFilter(servletRequest, servletResponse);
                            }
                            catch (Throwable e)
                            {
                                ReflectUtil.throwException(e);
                            }
                            return null;
                        }
                    });
                }
                catch (Exception e)
                {
                    ReflectUtil.throwException(e);
                }
            }
        }
        else
        {
            filterChain.doFilter(servletRequest, servletResponse);
        }
    }

    @Override
    public void destroy()
    {
    }

    public void setTccCommandHandler(TccCommandHandler tccCommandHandler)
    {
        this.tccCommandHandler = tccCommandHandler;
    }
}
